package ija.controller;

import ija.controller.types.GameState;
import ija.model.CheckersModel;
import ija.model.players.ComputerPlayer;
import ija.model.players.LocalPlayer;
import ija.model.players.Player;
import ija.model.players.RemotePlayer;
import ija.model.types.FigureColor;
import ija.model.types.FigureDirection;
import ija.net.Initiator;
import ija.net.Listener;
import ija.net.Networker;
import ija.view.CheckersContent;
import ija.view.elements.PlayerPanel;
import ija.xls.notation.GameMove;
import ija.xls.notation.NotationReader;
import ija.xls.notation.NotationReaderFactory;
import ija.xls.notation.NotationReaderFactory.NotationType;

import java.awt.FileDialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.swing.JCheckBox;

public class CheckersController extends NetGameController {

    protected CheckersContent view;
    protected CheckersModel model;
    protected NotationReader notation;
    protected Networker networker;
    protected CheckersRuller ruller;

    // region Constructors
    public CheckersController(MainController mc) {
        super(mc);
        this.setModel(new CheckersModel());
        this.notation = NotationReaderFactory.createNotationReader();
        this.networker = null;
        this.ruller = new CheckersRuller(this, this.getModel());
    }

    // endregion Constructors
    // region Setters
    public void setView(CheckersContent gc) {
        this.view = gc;
    }

    public void setModel(CheckersModel gm) {
        this.model = gm;
    }

    @Override
    public void setState(GameState gs) {
        super.setState(gs);
        if (this.view != null) {
            this.view.setState(gs);
        }
    }

    // endregion Setters
    // region Getters
    public NotationReader getNotationReader() {
        return this.notation;
    }

    @Override
    public CheckersContent getView() {
        return this.view;
    }

    public String getMessage() {
        return this.model.getMessage();
    }

    @Override
    public CheckersModel getModel() {
        return this.model;
    }

    // endregion Getters

    @Override
    public void initModel(FigureColor TopFc) {
        super.initModel(TopFc);
        this.getModel().initGame(TopFc);

        FigureColor BottomFc = (TopFc == FigureColor.BLACK ? FigureColor.WHITE : FigureColor.BLACK);

        LocalPlayer p = new LocalPlayer("Player 1", BottomFc, FigureDirection.FORWARD);
        this.model.setPlayer(0, p);
        p = new LocalPlayer("Player 2", TopFc, FigureDirection.BACKWARD);
        this.model.setPlayer(1, p);

    }

    public void setMessage(String message) {
        this.model.setMessage(message);
    }

    public void turnRound() {
        Player activePlayer = CheckersController.this.model.nextPlayer();
        if (activePlayer == null) {
            CheckersController.this.getModel().activatePlayer(FigureColor.WHITE);
            activePlayer = CheckersController.this.model.getActivePlayer();
        }
        this.ruller.storeAllMoves(activePlayer.getColor());
        if (this.ruller.allmoves.isEmpty()) {
            if (this.getModel().getDesk().getAllFigures(activePlayer.getColor()).isEmpty()) {
                this.setMessage("GAME OVER: " + activePlayer.getColor().toString() + " player "
                        + activePlayer.getName() + "is loser.");
            } else {
                this.setMessage("DRAW: No more moves.");
            }
        }
        this.setMessage("Player " + activePlayer.getName() + " is playing.");

        if (activePlayer instanceof ComputerPlayer) {
            this.setMessage("Počítač přemýšlí...");
            String sMove = this.ruller.chooseRandomMove();
            GameMove gm = this.notation.translate(sMove);
            this.getModel().move(gm);
            this.turnRound();
        }
    }

    // region Nested Classes
    public class StartGame extends NetGameController.StartGame {
        @Override
        public void actionPerformed(ActionEvent event) {
            boolean fromNet = false;

            if (event.getSource() instanceof Networker) {
                fromNet = true;
            }

            // if (CheckersController.this.status == GameStatus.GAMESETTINGS) {
            CheckersController.this.view.setEnabled(true);
            // CheckersController.this.view.setPlayersEditable(false);
            CheckersController.this.setState(GameState.GAMEINPROGRESS);
            CheckersController.this.view.setState(GameState.GAMEINPROGRESS);
            CheckersController.this.model.activatePlayer(FigureColor.WHITE);

            Player activePlayer = CheckersController.this.model.getActivePlayer();
            CheckersController.this.ruller.storeAllMoves(activePlayer.getColor());
            if (CheckersController.this.ruller.allmoves.isEmpty()) {
                if (CheckersController.this.getModel().getDesk()
                        .getAllFigures(activePlayer.getColor()).isEmpty()) {
                    CheckersController.this.setMessage("GAME OVER: "
                            + activePlayer.getColor().toString() + " player "
                            + activePlayer.getName() + "is loser.");
                } else {
                    CheckersController.this.setMessage("DRAW: No more moves.");
                }
            }
            CheckersController.this.setMessage("Player " + activePlayer.getName() + " is playing.");

            if (activePlayer instanceof ComputerPlayer) {
                CheckersController.this.setMessage("Počítač přemýšlí...");

                String sMove = CheckersController.this.ruller.chooseRandomMove();
                GameMove gm = CheckersController.this.notation.translate(sMove);
                CheckersController.this.getModel().move(gm);
                CheckersController.this.turnRound();
            }
            // CheckersController.this.turnRound();
            // CheckersController.this.view.getBoard().refresh(FigureColor.WHITE,
            // true);
            // }
            if (!fromNet) {
                try {
                    if (CheckersController.this.networker != null) {
                        ((Initiator) CheckersController.this.networker).sendStartGame();
                    }
                } catch (IOException e) {
                }
            }
        }
    }

    public class LoadGame extends NetGameController.LoadGame {
        @Override
        public void actionPerformed(ActionEvent event) {
            String filePath;
            FileDialog dLoad;
            boolean fromNet = false;

            if (event.getSource() instanceof Networker) {
                fromNet = true;
            }

            if (fromNet) {
                CheckersController.this.model
                        .setDesk(((Listener) CheckersController.this.networker).getInitDesk());
            } else {
                dLoad = new FileDialog(CheckersController.this.mainController.getMainWindow(),
                        "Load XML file ...", FileDialog.LOAD);

                dLoad.setFile("*.xml");

                dLoad.setFilenameFilter(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String name) {
                        return name.endsWith(".xml");
                    }
                });

                dLoad.setVisible(true);

                if ((dLoad.getDirectory() != null) && (dLoad.getFile() != null)) {
                    filePath = dLoad.getDirectory() + dLoad.getFile();
                    if (filePath.endsWith(".xml")) {
                        CheckersController.this.model.initInputXml(filePath);
                        if (CheckersController.this.getState() == GameState.JOINING) {
                            CheckersController.this.model.initGameXml();
                        } else {
                            CheckersController.this.model.initFromXml();
                        }
                        try {
                            ((Initiator) CheckersController.this.networker)
                                    .sendDeskInfo(CheckersController.this.model.getDesk());
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public class SaveGame extends NetGameController.SaveGame {
        @Override
        public void actionPerformed(ActionEvent event) {
            String filePath;
            FileDialog dSave;

            dSave = new FileDialog(CheckersController.this.mainController.getMainWindow(),
                    "Save as ...", FileDialog.SAVE);
            dSave.setFile("*.xml");

            dSave.setFilenameFilter(new FilenameFilter() {

                @Override
                public boolean accept(File dir, String name) {
                    return name.endsWith(".xml");
                }
            });

            dSave.setVisible(true);

            if ((dSave.getDirectory() != null) && (dSave.getFile() != null)) {
                filePath = dSave.getDirectory() + dSave.getFile();
                if (filePath.endsWith(".xml")) {
                    try {
                        CheckersController.this.model.initOutputXml(NotationType.IJA_NOTATION);
                        CheckersController.this.model.saveAllXmlAndWrite(filePath);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public class Host extends NetGameController.Host {
        @Override
        public void actionPerformed(ActionEvent event) {
            RemotePlayer p;
            int Port = 0;
            for (int i = 0; i < CheckersModel.PLAYERS_COUNT; i++) {
                if (CheckersController.this.model.getPlayer(i) instanceof RemotePlayer) {
                    p = (RemotePlayer) CheckersController.this.model.getPlayer(i);
                    Port = p.getPort();
                    break;
                }
            }
            if ((Port < 0) || (Port > 65535)) {
                CheckersController.this.setMessage("Nastavte PORT. <0-65535>");
                return;
            }

            try {
                ija.net.Listener listener = new ija.net.Listener(CheckersController.this);
                listener.init(Port);
                CheckersController.this.networker = listener;
                CheckersController.this.setState(GameState.CONNECTING);
            } catch (IOException ex) {
                System.err.println("CheckersController nepodarilo se vytvorit listener: "
                        + ex.getLocalizedMessage());
            }
        }
    }

    public class Join extends NetGameController.Join {
        @Override
        public void actionPerformed(ActionEvent event) {
            RemotePlayer p;
            int Port = 0;
            String IP = "";
            for (int i = 0; i < CheckersModel.PLAYERS_COUNT; i++) {
                if (CheckersController.this.model.getPlayer(i) instanceof RemotePlayer) {
                    p = (RemotePlayer) CheckersController.this.model.getPlayer(i);
                    IP = p.getIp();
                    Port = p.getPort();
                    break;
                }
            }
            if ((Port < 0) || (Port > 65535)) {
                CheckersController.this.setMessage("Nastavte PORT. <0-65535>");
                return;
            }
            if (IP == null) {
                CheckersController.this.setMessage("Nastavte IP!");
                return;
            }
            try {
                ija.net.Initiator initiator = new ija.net.Initiator(CheckersController.this);
                initiator.init(InetAddress.getByName(IP), Port, 0);
                CheckersController.this.networker = initiator;
                CheckersController.this.setState(GameState.GAMESETTINGS);
            } catch (IOException ex) {
                System.err.println("CheckersController - Nepodarilo se vytvorit Initiator: "
                        + ex.getLocalizedMessage());
                CheckersController.this.setMessage(ex.getLocalizedMessage());
            }
        }
    }

    public class Move extends NetGameController.Move {

        @Override
        public void actionPerformed(ActionEvent event) {
            String moveString = null;
            boolean fromNet = false;

            if (CheckersController.this.getState() != GameState.GAMEINPROGRESS) {
                return;
            }
            // Zjistim od koho udalost dosla a nastavim dle toho move
            if (event.getSource() instanceof Networker) {
                fromNet = true;
                moveString = event.getActionCommand();
            } else {
                moveString = CheckersController.this.view.GetMove();
            }

            GameMove gm = CheckersController.this.notation.translate(moveString);
            if (gm == null) {
                CheckersController.this.setMessage("Nepodařilo se dekódovat Move: " + moveString);
                return;
            }
            if (CheckersController.this.model.move(gm) == false) {
                CheckersController.this.setMessage("Neplatný tah: " + moveString);
                return;
            }

            CheckersController.this.turnRound();

            // Pokud mi zprava nedosla od networkeru a druhy hrac je
            // networker,
            // preposlu mu jej
            if (!fromNet
                    && (CheckersController.this.model.getActivePlayer() instanceof RemotePlayer)) {
                try {
                    CheckersController.this.networker.sendGameMove(moveString);
                } catch (IOException ex) {
                    CheckersController.this.setMessage("Chyba spojení při zasílání Move.");
                }
            }
        }
    }

    public class SetPlayer extends NetGameController.SetPlayer {
        @Override
        public void onPlayerChanged(PlayerPanel pp, Player p, int id) {

            if (pp != null) { // prislo z GUI
                CheckersController.this.getModel().setPlayer(id, p.duplicate());
                CheckersController.this.getModel().initGame(
                        CheckersController.this.getModel().getTopPlayer().getColor());
                try {
                    if (CheckersController.this.networker != null) {
                        CheckersController.this.networker.sendPlayerInfo(p);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else { // prislo z Networkera
                for (int i = 0; i < CheckersModel.PLAYERS_COUNT; i++) {
                    if (CheckersController.this.model.getPlayer(i) instanceof RemotePlayer) {
                        RemotePlayer rp = (RemotePlayer) CheckersController.this.model.getPlayer(i);
                        rp.setColor(p.getColor());
                        rp.setDirection(p.getDirection());
                        rp.setName(p.getName());
                        CheckersController.this.model.setPlayer(i, rp);
                    }

                }
                if ((CheckersController.this.networker != null)
                        && (CheckersController.this.getState() == GameState.HOSTING)) {
                    for (int i = 0; i < CheckersModel.PLAYERS_COUNT; i++) {
                        p = CheckersController.this.model.getPlayer(i);
                        if (p instanceof LocalPlayer) {
                            try {
                                CheckersController.this.networker.sendPlayerInfo(p);
                            } catch (IOException e) {
                            }
                            break;
                        }
                    }
                }
            }
        }
    }

    public class MainMenu extends NetGameController.MainMenu {

        @Override
        public void actionPerformed(ActionEvent event) {
            CheckersController.this.mainController.showMainMenu();
        }
    }

    public class Accept {
        public void ActionPerformed(ActionEvent event) {
            boolean fromNet = false;
            if (event.getSource() instanceof Networker) {
                fromNet = true;
            }

            if (fromNet) {
                CheckersController.this.setMessage("Connection ACCEPTed");
                CheckersController.this.setState(GameState.JOINING);
                Player p;
                for (int i = 0; i < CheckersModel.PLAYERS_COUNT; i++) {
                    p = CheckersController.this.model.getPlayer(i);
                    if (p instanceof LocalPlayer) {
                        try {
                            CheckersController.this.networker.sendPlayerInfo(p);
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        break;
                    }
                }
                try {
                    ((Initiator) CheckersController.this.networker)
                            .sendDeskInfo(CheckersController.this.model.getDesk());
                } catch (IOException e) {
                    System.out.println("Chyba");
                    e.printStackTrace();
                }
            } else {
                try {
                    CheckersController.this.networker.sendAccept();

                } catch (IOException e1) {
                    CheckersController.this.setMessage(CheckersController.this.getMessage()
                            + "UnableToSend: ACCEPT");
                }
                CheckersController.this.setState(GameState.HOSTING);
            }
        }
    }

    public class Deny {
        public void ActionPerformed(ActionEvent event) {
            boolean fromNet = false;
            if (event.getSource() instanceof Networker) {
                fromNet = true;
            }

            if (!fromNet) {
                try {
                    CheckersController.this.networker.sendDeny();
                } catch (IOException e1) {
                }
            } else {
                CheckersController.this.setMessage("Connection DENYed");
            }

            try {
                CheckersController.this.networker.closeServer();

            } catch (IOException e1) {
            }
            CheckersController.this.networker = null;
            CheckersController.this.setState(GameState.GAMESETTINGS);
        }
    }

    public class Confirm implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            boolean fromNet = false;
            boolean checked = false;
            if (e.getSource() instanceof Networker) {
                fromNet = true;
            }

            if (!fromNet) {
                if (e.getSource() instanceof JCheckBox) {
                    checked = ((JCheckBox) e.getSource()).isSelected();
                    System.out.println("fromGUI" + String.valueOf(checked));
                    CheckersController.this.setMessage("fromGUI" + String.valueOf(checked));
                }
                try {
                    ((Listener) CheckersController.this.networker).sendConfirm(checked);
                } catch (IOException e1) {
                }
            } else {
                checked = Boolean.parseBoolean(e.getActionCommand());
                System.out.println("fromNET: " + String.valueOf(checked));
                CheckersController.this.setMessage("fromNET" + String.valueOf(checked));
            }
        }
    }

    public class AskForConnection {
        @SuppressWarnings("unused")
        public void ActionPerformed(ActionEvent e) {
            String[] addrInfo = e.getActionCommand().split(":");
            String IP = null;
            String Port = null;
            if (addrInfo.length != 2) {

            } else {
                IP = addrInfo[0];
                Port = addrInfo[1];
            }
            CheckersController.this.setMessage("AskedForConnection: IP:" + IP + " Port: " + Port);
            try {
                CheckersController.this.networker.setClient(IP, Integer.parseInt(Port));
            } catch (NumberFormatException | UnknownHostException e1) {
                CheckersController.this.setMessage(CheckersController.this.getMessage()
                        + "Unable To Set Client ");
            }
            // raise Dialog -> getAnswer
            if (true) {
                Accept a = CheckersController.this.createAcceptListener();
                a.ActionPerformed(new ActionEvent(this, 0, null));
            } else {
                Deny d = CheckersController.this.createDenyListener();
                d.ActionPerformed(new ActionEvent(this, 0, null));
            }
        }
    }

    public class ExitGame extends NetGameController.ExitGame {

        @Override
        public void actionPerformed(ActionEvent event) {
            boolean fromNet = false;
            if (event.getSource() instanceof Networker) {
                fromNet = true;
            }
            if (CheckersController.this.networker == null) {
                return;
            }
            if (fromNet) {
                CheckersController.this.setMessage("Konec hry: " + event.getActionCommand());
                // CheckersController.this.mainController.showExitDialog();
            } else {
                try {
                    CheckersController.this.networker.sendEndGame("Nemám čas na blbosti!");
                } catch (IOException e) {
                }
            }

        }
    }

    // endregion Nested Classes

    // region Factories
    @Override
    public StartGame createStartGameListener() {
        return new StartGame();
    }

    @Override
    public Host createHostListener() {
        return new Host();
    }

    @Override
    public Join createJoinListener() {
        return new Join();
    }

    @Override
    public Move createMoveListener() {
        return new Move();
    }

    @Override
    public SaveGame createSaveGameListener() {
        return new SaveGame();
    }

    @Override
    public LoadGame createLoadGameListener() {
        return new LoadGame();
    }

    @Override
    public SetPlayer createSetPlayerListener() {
        return new SetPlayer();
    }

    public Accept createAcceptListener() {
        return new Accept();
    }

    public Deny createDenyListener() {
        return new Deny();
    }

    @Override
    public Confirm createConfirmListener() {
        return new Confirm();
    }

    public AskForConnection createAskForConnListener() {
        return new AskForConnection();
    }

    @Override
    public MainMenu createMainMenuListener() {
        return new MainMenu();
    }

    @Override
    public ExitGame createExitGameListener() {
        return new ExitGame();
    }

    // endregion Factories

    /*
     * * public class GiveUp extends NetGameController.GiveUp {
     * 
     * @Override public void actionPerformed(ActionEvent event) {
     * System.out.println("Checkers: GiveUp"); } }
     * 
     * @Override public GiveUp createGiveUpListener() { return new GiveUp(); }
     */

}
